package fun.tan90.easy.binlog.worker.job;

import cn.hutool.core.util.StrUtil;
import fun.tan90.easy.binlog.base.constants.EasyBinlogConstants;
import fun.tan90.easy.binlog.worker.client.EbWorker;
import lombok.Builder;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.actuate.metrics.MetricsEndpoint;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * description TODO
 * company 铁人科技
 *
 * @author 陈浩杰
 * @date 2023/9/19 21:47
 */
@Slf4j
public abstract class MetricJob {

    @Resource
    EbWorker ebWorker;

    @Resource
    MetricsEndpoint metricsEndpoint;

    protected abstract void task();

    protected void doTask(String tableName, String... tags) {
        if (!ebWorker.getConfig().getMetric()) {
            return;
        }
        String fieldSet = generateField();
        if (!StringUtils.hasLength(fieldSet)) {
            return;
        }
        String tagSet = generateTag(tags);
        String schemalessSql = StrUtil.format("{},{} {} {}", tableName, tagSet, fieldSet, System.currentTimeMillis());
        ebWorker.send(EasyBinlogConstants.METRIC_COLLECT, schemalessSql);
    }

    protected abstract Map<String, MetricTag> rowMap();

    private String generateTag(String... tags) {
        List<String> tagList = new ArrayList<>();
        tagList.add(StrUtil.format("work_id={}", ebWorker.getWorkId()));
        for (String tag : tags) {
            String[] split = tag.split(":");
            tagList.add(StrUtil.format("{}={}", split[0], split[1]));
        }
        return String.join(",", tagList);
    }

    private String generateField() {
        Map<String, MetricTag> rowMap = rowMap();
        if (CollectionUtils.isEmpty(rowMap)) {
            return "";
        }
        List<String> fieldList = new ArrayList<>();
        for (Map.Entry<String, MetricTag> entry : rowMap.entrySet()) {
            String requiredMetricName = entry.getValue().getRequiredMetricName();
            MetricsEndpoint.MetricResponse metric = metricsEndpoint.metric(requiredMetricName, entry.getValue().getTag());
            fieldList.add(StrUtil.format("{}={}", entry.getKey(), metric.getMeasurements().get(0).getValue()));
        }
        return String.join(",", fieldList);
    }

    @Data
    @Builder
    public static class MetricTag {

        private String requiredMetricName;

        private List<String> tag;
    }
}
